<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>网络结构图</title>
    <style>

        @-webkit-keyframes twinkling{   /*透明度由0到1*/
            0%{
                opacity:0.1;                /*透明度为0*/
            }
            100%{
                opacity:1;              /*透明度为1*/
            }
        }
        .node circle {
            cursor: pointer;
            fill: #d43433;
            stroke: steelblue;
            stroke-width: 2px;
        }

        .node text {
            font-size: 12px;
        }

        .link {
            fill: none;
            stroke: #ccc;
            stroke-width: 1.5px;
        }
    </style>
</head>
<body>
<script src="d3.min.js"></script>
<script>
    var width = 600;
    var height = 500;

    //边界空白
    var padding = {left: 80, right:50, top: 20, bottom: 20 };

    var svg = d3.select("body")
            .append("svg")
            .attr("width", width + padding.left + padding.right)
            .attr("height", height + padding.top + padding.bottom)
            .append("g")
            .attr("transform","translate("+ padding.left + "," + padding.top + ")");

    //树状图布局
    var tree = d3.layout.tree()
            .size([height, width]);

    //对角线生成器
    var diagonal = d3.svg.diagonal()
            .projection(function(d) { return [d.y, d.x]; });

    function createWeb(jsonData) {
        var root = JSON.parse(jsonData);

        //给第一个节点添加初始坐标x0和x1
        root.x0 = height / 5;
        root.y0 = 0;

        //以第一个节点为起始节点，重绘
        redraw(root);

        //重绘函数

        function redraw(source) {

            /*
             (1) 计算节点和连线的位置
             */
            //应用布局，计算节点和连线
            var nodes = tree.nodes(root);
            var links = tree.links(nodes);

            //重新计算节点的y坐标
            nodes.forEach(function(d) { d.y = d.depth * 120; });
            /*
             （2） 节点的处理
             */

            function getChinese(d) {
                if(d == "end")
                {
                    return "报警器";
                }else if(d== "coordinator")
                {
                    return "协调器";
                } else if (d == "router") {
                    return "报警器";
                }
            }

            //获取节点的update部分
            var nodeUpdate = svg.selectAll(".node")
                    .data(nodes, function (d) {
                        return getChinese(d.nodetype) + " : " + d.address;
                    });

            //获取节点的enter部分
            var nodeEnter = nodeUpdate.enter();

            //获取节点的exit部分
            var nodeExit = nodeUpdate.exit();

            //1. 节点的 Enter 部分的处理办法
            var enterNodes = nodeEnter.append("g")
                    .attr("class", "node")
                    .attr("transform", function (d) {
                        return "translate(" + source.y0 + "," + source.x0 + ")";
                    });



            enterNodes.append("circle")
                    .attr("r", 0)
                    .style("fill", function (d) {
                        if (d.nodetype == "coordinator") {
                            return "#9D55B8";
                        } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Alarm") {
                            return "#FF3C2D";
                        } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Arming") {
                            return "#4BCB26";
                        } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "DisArming") {
                           return "#AAAAB0";
                        } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Normal") {
                           return "#1E86DF";
                        }
                    }).style("stroke", function (d) {
                        if (d.nodetype == "coordinator") {
                             return "#9D55B8";
                        } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Alarm") {
                             return "#FF3C2D";
                        } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Arming") {
                             return "#4BCB26";
                        } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "DisArming") {
                             return "#AAAAB0";
                        } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Normal") {
                             return "#1E86DF";
                        }

            });

            enterNodes.append("text")
                    .attr("x", function (d) {
                        if(d.nodetype == "coordinator"){
                            return 16;
                        }
                        return d.children || d._children ? -7 : 7;
                    }).attr("y", "16")
                    .attr("dy", ".35em")
                    .attr("text-anchor", function (d) {
                        if(d.nodetype == "coordinator"){
                            return "middle";
                        }
                        return d.children || d._children ? "end" : "start";
                    })
                    .text(function (d) {
                        return getChinese(d.nodetype) + " : " + d.address;
                    })
                    .style("fill-opacity", 0);


            //2. 节点的 Update 部分的处理办法
            var updateNodes = nodeUpdate.transition()
                    .duration(500)
                    .attr("transform", function (d) {
                        return "translate(" + d.y + "," + d.x + ")";
                    });

            updateNodes.select("circle")
                    .attr("r", 8)
                    .attr("class","circle")
                    .attr("id", function (d) {
                        return d.address;
                    })
                    .style("fill", function (d) {
                           if (d.nodetype == "coordinator") {
                           return "#9D55B8";
                           } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Alarm") {
                           return "#FF3C2D";
                           } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Arming") {
                           return "#4BCB26";
                           } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "DisArming") {
                           return "#AAAAB0";
                           } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Normal") {
                           return "#1E86DF";
                           }

                    }).style("stroke", function (d) {
                             if (d.nodetype == "coordinator") {
                             return "#9D55B8";
                             } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Alarm") {
                             return "#FF3C2D";
                             } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Arming") {
                             return "#4BCB26";
                             } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "DisArming") {
                             return "#AAAAB0";
                             } else if ((d.nodetype == "end" || d.nodetype == "router") && d.state == "Normal") {
                             return "#1E86DF";
                             }
            }).style("-webkit-animation",function (d) {
                if (d.state == "Alarm")
                {
                    return "twinkling 1s infinite ease-in-out";
                }else{
                    return "twinkling 0s infinite ease-in-out";
                }
            });

            updateNodes.select("text")
                    .style("fill-opacity", 1);

            //3. 节点的 Exit 部分的处理办法
            var exitNodes = nodeExit.transition()
                    .duration(500)
                    .attr("transform", function (d) {
                        return "translate(" + source.y + "," + source.x + ")";
                    })
                    .remove();

            exitNodes.select("circle")
                    .attr("r", 0);

            exitNodes.select("text")
                    .style("fill-opacity", 0);
            /*
             （3） 连线的处理
             */
            //获取连线的update部分
            var linkUpdate = svg.selectAll(".link")
                    .data(links, function(d){
                        return getChinese(d.target.nodetype) + " : " + d.target.address; })
                    .attr("x0",function (d) {
                        return d.target.x;
                    });

            //获取连线的enter部分
            var linkEnter = linkUpdate.enter();

            //获取连线的exit部分
            var linkExit = linkUpdate.exit(); //1. 连线的 Enter 部分的处理办法

            linkEnter.insert("path", ".node")
                    .attr("class", "link")
                    .attr("d", diagonal)
                    .transition()
                    .attr("x0",function (d) {
                        return d.target.x;
                    })
                    .duration(500);
            //2. 连线的 Update 部分的处理办法
            linkUpdate.transition()
                    .duration(500)
                    .attr("d", diagonal); //3. 连线的 Exit 部分的处理办法

            linkExit.transition()
                    .duration(500)
                    .attr("d",diagonal)
                    .remove();
            /*
             （4） 将当前的节点坐标保存在变量x0、y0里，以备更新时使用
             */
            nodes.forEach(function(d) {
                d.x0 = d.x;
                d.y0 = d.y;
            });
        }
        return "success";
    }


    //切换开关，d 为被点击的节点
    function toggle(d){
        if(d.children){ //如果有子节点
            d._children = d.children; //将该子节点保存到 _children
            d.children = null;  //将子节点设置为null
        }else{
            //如果没有子节点
            d.children = d._children; //从 _children 取回原来的子节点
            d._children = null; //将 _children 设置为 null
        }
    }



    //createWeb(jsonData6);



</script>
</body>
</html>